import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { RESPONSE_CODE } from '@nbase/shared';
import { LoggerFactory } from '../../logger/logger.factory';
import { RequestUtil } from '../utils/request.util';

/**
 * 全局异常过滤器
 *
 * 采用混合方案：
 * - HTTP 状态码表达请求级别状态（200/401/403/500）
 * - 业务状态码表达业务级别状态（0, 1001-9999）
 *
 * 规则：
 * - 业务异常：HTTP 200 + 业务码（1001-5999）
 * - 系统异常：HTTP 4xx/5xx + 相同的 code
 *
 * 兼容性：
 * - 同时支持 Fastify 和 Express
 */
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  private readonly logger = LoggerFactory.get(HttpExceptionFilter, 'http');

  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    let httpStatus: number;
    let code: number;
    let message: string;

    if (exception instanceof HttpException) {
      httpStatus = exception.getStatus();
      const exceptionResponse = exception.getResponse();

      // 如果异常响应包含自定义 code（业务异常）
      if (typeof exceptionResponse === 'object' && 'code' in exceptionResponse) {
        code = (exceptionResponse as any).code;
        message = (exceptionResponse as any).message;
      } else {
        // 系统异常：使用 HTTP 状态码作为业务码
        code = httpStatus;
        message =
          typeof exceptionResponse === 'string'
            ? exceptionResponse
            : (exceptionResponse as any).message || exception.message;
      }
    } else {
      // 未知异常
      httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
      code = RESPONSE_CODE.INTERNAL_ERROR;
      message = '服务器内部错误';
    }

    // 记录错误日志（结构化日志）
    this.logger.error(
      {
        code,
        httpStatus,
        method: request.method,
        url: request.url,
        message,
        userAgent: request.headers?.['user-agent'],
        ip: RequestUtil.getClientIp(request),
        error: exception instanceof Error ? {
          name: exception.name,
          message: exception.message,
          stack: exception.stack,
        } : exception,
      },
      `[${code}] ${request.method} ${request.url} - ${message}`
    );

    // 统一响应格式（兼容 Fastify 和 Express）
    response.status(httpStatus).send({
      code,
      data: null,
      message,
      timestamp: new Date().toISOString(),
    });
  }
}

